/** 
 * Parser.java Created by iweerarathna on Aug 31, 2011.
 * 
 * Copyright (c) 2011 Virtusa Corporation. All Rights Reserved.<br><br>. 
 * 
 */
package org.uim.cricket.analyzer.parsers;

import java.io.*;
import java.util.*;

import org.uim.cricket.analyzer.analyze.Analyzer;
import org.uim.cricket.analyzer.analyze.report.XMLAnalyzerReporter;
import org.uim.cricket.analyzer.parsers.match.CricketMatchParsable;
import org.uim.cricket.analyzer.report.DefaultReportFactory;
import org.uim.cricket.analyzer.report.MatchReportable;
import org.uim.cricket.analyzer.report.XMLMatchReporter;
import org.uim.cricket.analyzer.validate.MatchValidator;
import org.uim.cricket.entities.MatchPlayer;
import org.uim.cricket.entities.match.CricketMatch;
import org.uim.cricket.util.io.FileOpener;

/**
 * Start point of the parser.
 * @version 
 * @author iweerarathna
 */
public class Parser {

	public static String SCORECARD_BEAN_CONFIG_FILE = "../config/parser-beans.xml";
	public static String ANALYZER_BRAN_CONFIG_FILE = "../config/analyzer-beans.xml";
	
	static {
		System.setProperty("org.apache.commons.logging.Log",
        						"org.apache.commons.logging.impl.NoOpLog");
	}
	
	/**
	 * Starts the execution of parser.
	 * <p>
	 * Full execution of this parser will be.
	 * java -jar [jarname] -type:[typeOfScoreCard] -f:[Outputfile_type] [inputfile] [outputfile]
	 * </p>
	 * @param args At least there must be 2 arguments.
	 *          Argument[0] = "-type:[Type_of_scorecard_parser]" --- default: "default".
	 *          Argument[1] = "-f:[Output_file_type]" ---- if the input and output is file based. Output file type. (default: "xml").
	 *                Argument[2] = "input file"
	 *                Argument[3] = "output file"
	 *                 
	 */
    public static void main(String[] args) {
        Plogger.debug(Plogger.repeat("+", 80));
        Plogger.debug(Plogger.repeat("+", 80));
        Plogger.debug("");
        Plogger.debug("> Started new instance of parser");
        
        if (args == null || args.length == 0) {
            Plogger.error("No arguments found for cricket-analyzer-parser!");
            Plogger.debug("Application terminating");
            Plogger.debug("end.");
            return;
        }
        
        Plogger.debug("> Input arguments: ");
        for (int i=0;i<args.length;i++) {
            Plogger.debug("arg [" + i + "] : " + args[i]); 
        }
        
        if (args.length < 3) {
            Plogger.error("Number of arguments must be greater than 2!");
            Plogger.debug("Application terminating");
            Plogger.debug("end.");
            return;
        }
        
        InputArgumentParser inArgs = new InputArgumentParser(args);
        try {
        	
        	inArgs.parseArguments();
        	
        } catch (Exception ex) {
        	Plogger.error("!!! Error occured!. ");
        	Plogger.error(ex.getMessage(), ex);
        	Plogger.debug("Application terminating");
            Plogger.debug("end.");
        	return;
        }
        
        CricketMatchParsable scoreCardParser = null;
        AbstractScoreCardFactory scFactory = new BeanScoreCardFactory(SCORECARD_BEAN_CONFIG_FILE);
        
        try {
            
        	if (inArgs.getScoreCardParserType() != null) {
        		scoreCardParser = scFactory.createScoreCardParser(inArgs.getScoreCardParserType());
        	} else {
        		throw new Exception("Scorecard type can't be NULL!");
        	}
            
        } catch (Exception e) {
            Plogger.error("Following error occured", e);
            Plogger.debug("Application terminating");
            Plogger.debug("end.");
            return;
        }
        
        MatchReportable report = null;
        String inputFile = inArgs.getInputScoreCardFile();
        String output = inArgs.getReportScoreCardFile();
        CricketMatch match = null;
        
        try {
        	
        	report = new DefaultReportFactory().createReport(inArgs.getReportScoreCardType());
        	makePath(output);
        	if (report instanceof XMLMatchReporter) {
                ((XMLMatchReporter)report).setXmlFile(output);
            }
        	
        } catch (Exception e) {
            
            Plogger.error("Unknown report type '" + args[1] + "'!", e);
            Plogger.debug("Application terminating");
            Plogger.debug("end.");
            return;
            
        }
        
        Plogger.debug(repeat("-", 50)); 
        Plogger.debug("Input: " + inputFile);
        Plogger.debug("Output: " + output);
        Plogger.debug(repeat("-", 50)); 
        
        // Opens the input file...
        StringBuilder source = null;
        try {
            
            FileOpener fo = new FileOpener(inputFile);
            source = fo.open();
            
        } catch (IOException io) {
            
            Plogger.error("Error occured while opening input file!");
            Plogger.error(inputFile);
            Plogger.error("", io);
            Plogger.debug("Application terminating");
            Plogger.debug("end.");
            return;
            
        }
        
        try {

            Plogger.debug(repeat("-", 50)); 
            Plogger.debug("Starting parser...");
            Plogger.debug(repeat("-", 50)); 
            
            match = scoreCardParser.parseMatch(source);
            
            Plogger.debug(repeat("-", 50)); 
            Plogger.debug("Completed parsing.");
            Plogger.debug(repeat("-", 50)); 
            
            Plogger.debug("");

        } catch (Exception e) {
            
            Plogger.error("Error occured while parsing!", e);
            Plogger.debug("Application terminating");
         
        }
        
        try {
        	Plogger.debug("Reporting started...");
            Plogger.debug(repeat("-", 50));
            
            report.reportMatch(match);
            
            Plogger.debug(repeat("-", 50));
            Plogger.debug("Reporting completed.");
            
        } catch (Exception ex) {
        	Plogger.error("Error occured in reporting!", ex);
        	Plogger.debug("end.");

        }
        
        Map<String, List<MatchPlayer>> players = null;
        if (inArgs.isDoAnalysis()) {
        	
        	Plogger.debug("analyzer executed!");
        	
        	try {
        		
        		Analyzer analyzer = new Analyzer(match);
            	FetchAnalyzerBeans analBeans = new FetchAnalyzerBeans(ANALYZER_BRAN_CONFIG_FILE);
            	analBeans.loadBeans();
            	analyzer.setExecutor(analBeans.fetchExecutor(inArgs.getAnalyzerExecutorType()));
            	analyzer.setReporter(new XMLAnalyzerReporter());
            	
        		analyzer.analyze();
        		
        		players = analyzer.getPlayerData();
        		Plogger.debug("Successfully execued analyzer!");
        		
        	} catch (Exception ex) {
        		Plogger.error("Analyzer executor failed with following exception!");
        		Plogger.error(ex.getMessage(), ex);
        		Plogger.debug("end.");
        		
        	}
        	
        }
        
        if (inArgs.isDoValidation()) {
        	
        	try {

                Plogger.debug(repeat("-", 50)); 
                Plogger.debug("Starting validator...");
                Plogger.debug(repeat("-", 50)); 
                
                MatchValidator validator = new MatchValidator(match, players, inArgs.getValidationBeanID());
                validator.doValidation();
                
                Plogger.debug(repeat("-", 50)); 
                Plogger.debug("Completed validating.");
                Plogger.debug(repeat("-", 50)); 

            } catch (Exception e) {
                
                Plogger.error("Error occured while validating!");
                Plogger.error(e.toString());
                Plogger.debug("end.");
                
            }
        	
        } else {
        	
        	Plogger.printHardWarn("Validation ignored!");
        }
        
        
        Plogger.debug("end.");
    }
    
    private static String repeat(String s, int count) {
        StringBuilder sb = new StringBuilder();
        for (int i=0;i<count;i++) {
            sb.append(s);
        }
        return sb.toString();
    }
    
    private static void makePath(String path) {
    	File f = new File(path);
    	if (!f.isDirectory()) {
    		f = f.getParentFile();
    	}
    	
    	if (f.exists()) return;
    	
    	f.mkdirs();
    }
    
}
